﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using Lib.Approval;
using Lib.Helper;
using Lib.Mail;
using MSIACCSL2.CoaServices;
using MSIACCSL2.Command;
using MSIACCSL2.ItemServices;
using MSIACCSL2.SatuanServices;
using MSIACCSL2.Struct;
using MSIACCSL2.SubGroupServices;
using MSIACCSL2.Views.Item;
using WcfService1.DTO;
using DeleteCompletedEventArgs = MSIACCSL2.ItemServices.DeleteCompletedEventArgs;
using GetListByCriteriaCompletedEventArgs = MSIACCSL2.ItemServices.GetListByCriteriaCompletedEventArgs;
using GetListCompletedEventArgs = MSIACCSL2.ItemServices.GetListCompletedEventArgs;
using SaveCompletedEventArgs = MSIACCSL2.ItemServices.SaveCompletedEventArgs;

namespace MSIACCSL2.ViewModels
{
    public class ItemViewModel : ViewModelBase
    {
        #region Delegates

        public delegate void Completed(Object param);

        #endregion

        private static string OrderType;
        private static string PropertySort;
        public static Mode mode;
        private static ItemDTO _itemDto;
        private static Add frmAdd;
        public static Completed OnSearchCompleted;
        private static Search frmSearch;
        private readonly CoaServicesClient CoaClient;
        private readonly SatuanServicesClient SatuanClient;
        private readonly SubGroupServiceClient SubGroupClient;
        private readonly ItemServicesClient client;
        private readonly ValidationHandler validationHandler;
        private int CurrentPage;
        private ObservableCollection<int> Pages;
        private ObservableCollection<CoaDTO> _Coas;
        private bool _IsBusy;

        private ObservableCollection<SatuanDTO> _Satuans;
        private ObservableCollection<SubGroupDTO> _groups;
        private PagedCollectionView _items;
        private PagedCollectionView _pageSources;
        private Dictionary<string, object> criteria;
        private string expression;
        private ObservableCollection<CoaDTO> _CoasExpense;
        private ObservableCollection<CoaDTO> _CoasSalesReturn;
        private ObservableCollection<CoaDTO> _CoasSales;
        private ObservableCollection<CoaDTO> _CoasHpp;
        private ObservableCollection<CoaDTO> _CoasInventory;


        public ItemViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                client = new ItemServicesClient();
                SubGroupClient = new SubGroupServiceClient();
                SatuanClient = new SatuanServicesClient();
                CoaClient = new CoaServicesClient();

                OnPageChanged = new DelegateCommand(PageIndexChanged, CanPageIndexChanged);
                Save = new DelegateCommand(SaveSubGroup, CanSave);
                New = new DelegateCommand(NewSubGroup, CanNew);
                Edit = new DelegateCommand(EditSubGroup, CanEdit);
                Unload = new DelegateCommand(Release, CanUnload);
                SearchCommand = new DelegateCommand(SearchSubGroup, CanSearch);
                SearchResultCommand = new DelegateCommand(SearchResult, CanSearchResult);
                validationHandler = new ValidationHandler();

                //Kalo lagi di Edit jangan diload Datanya tar nimpa

                if (mode == Mode.Edit || mode == Mode.Search || mode == Mode.Add)
                {
                    GetGroupList();
                    GetSatuanList();
                    GetCOAInventory();
                    GetCOAHpp();
                    GetCOAExpense();
                    GetCOASales();
                    GetCOASalesReturn();
                }
                else
                {
                    GetList(1, null);
                }
            }
        }

        public PagedCollectionView Items
        {
            get { return _items; }

            private set
            {
                if (Items == value) return;
                _items = value;

                int i = (CurrentPage*30);
                foreach (object subGroup in Items)
                {
                    i += 1;

                    ((ItemDTO) subGroup).No = i;
                }

                FirePropertyChanged("Items");
                Items.CollectionChanged += Item_CollectionChanged;
            }
        }


        public PagedCollectionView PageSources
        {
            get { return _pageSources; }
            private set
            {
                if (PageSources == value) return;
                _pageSources = value;
                FirePropertyChanged("PageSources");
            }
        }


        public ObservableCollection<SubGroupDTO> SubGroups
        {
            get { return _groups; }
            private set
            {
                if (SubGroups == value) return;
                _groups = value;
                FirePropertyChanged("SubGroups");
            }
        }


        public bool IsBusy
        {
            get { return _IsBusy; }
            internal set
            {
                _IsBusy = value;
                FirePropertyChanged("IsBusy");
            }
        }

        public long RecordCount { get; set; }

        //Buat binding ke child form waktu mau edit
        public static ItemDTO ItemDto
        {
            get { return _itemDto; }
            private set
            {
                if (ItemDto == value) return;
                _itemDto = value;
                FirePropertyChanged2("ItemDto");
            }
        }


        public ObservableCollection<SatuanDTO> Satuans
        {
            get { return _Satuans; }
            private set
            {
                if (Satuans == value) return;
                _Satuans = value;
                FirePropertyChanged("Satuans");
            }
        }

        public ObservableCollection<CoaDTO> CoasSales
        {
            get { return _CoasSales; }
            private set
            {
                if (CoasSales == value) return;
                _CoasSales = value;
                FirePropertyChanged("CoasSales");
            }
        }

        public ObservableCollection<CoaDTO> CoasHpp
        {
            get { return _CoasHpp; }
            private set
            {
                if (CoasHpp == value) return;
                _CoasHpp = value;
                FirePropertyChanged("CoasHpp");
            }
        }

        public ObservableCollection<CoaDTO> CoasInventory
        {
            get { return _CoasInventory; }
            private set
            {
                if (CoasInventory == value) return;
                _CoasInventory = value;
                FirePropertyChanged("CoasInventory");
            }
        }


        public ObservableCollection<CoaDTO> CoasSalesReturn
        {
            get { return _CoasSalesReturn; }
            private set
            {
                if (CoasSalesReturn == value) return;
                _CoasSalesReturn = value;
                FirePropertyChanged("CoasSalesReturn");
            }
        }

        public ObservableCollection<CoaDTO> CoasExpense
        {
            get { return _CoasExpense; }
            private set
            {
                if (CoasExpense == value) return;
                _CoasExpense = value;
                FirePropertyChanged("CoasExpense");
            }
        }


        public ICommand OnPageChanged { get; set; }
        public ICommand Save { get; set; }
        public ICommand New { get; set; }
        public ICommand Edit { get; set; }
        public ICommand Unload { get; set; }
        public ICommand SearchCommand { get; set; }
        public ICommand SearchResultCommand { get; set; }

        public string Error
        {
            get { return null; }
        }

        public string this[string columnName]
        {
            get
            {
                if (validationHandler.BrokenRuleExists(columnName))
                {
                    return validationHandler[columnName];
                }
                return null;
            }
        }

        public void Complete(Object param)
        {
            OnSearchCompleted(param);
        }

        private void Item_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (((PagedCollectionView) sender).SortDescriptions.Count > 0)
            {
                if (((PagedCollectionView) sender).SortDescriptions[0].PropertyName.ToLower() == "no") return;

                PropertySort = ((PagedCollectionView) sender).SortDescriptions[0].PropertyName;
                if (string.IsNullOrEmpty(OrderType))
                {
                    OrderType = "ASC";
                }
                else
                {
                    OrderType = OrderType == "ASC" ? OrderType = "DESC" : OrderType = "ASC";
                }
                GetList(1, PropertySort);
            }
        }


        public void SaveSubGroup(Object itemDTO)
        {
            ItemDto = (ItemDTO) itemDTO;
            ItemDto.created_by = GlobalVar.User.UserID;
            ItemDto.modified_by = GlobalVar.User.UserID;
            client.SaveCompleted += client_SaveCompleted;
            client.SaveAsync((ItemDTO) itemDTO);
        }

        private void client_SaveCompleted(object sender, SaveCompletedEventArgs e)
        {
            client.SaveCompleted -= client_SaveCompleted;
            if (e.Result)
            {
                MessageBox.Show("Success");
                frmAdd.DialogResult = true;
                Refresh();
                EventAggregator.PublishMessage("LoadItemFor", null);
            }
        }


        public void GetList(int? page, string sortProp)
        {
            IsBusy = true;
            client.GetListCompleted += client_GetListCompleted;
            client.GetListAsync(page ?? 1, sortProp, OrderType);
        }

        private void client_GetListCompleted(object sender, GetListCompletedEventArgs e)
        {
            RecordCount = e.recordCount;
            if (PageSources == null) CreatePageNumber();
            client.GetListCompleted -= client_GetListCompleted;
            Items = new PagedCollectionView(e.Result);
            IsBusy = false;
            Complete(this);
        }


        private void NewSubGroup(Object param)
        {
            mode = Mode.Add;
            ItemDto = new ItemDTO();
            frmAdd = new Add();
            frmAdd.Show();
        }


        public static void EditSubGroup(Object param)
        {
            mode = Mode.Edit;
            ItemDto = (ItemDTO) param;
            ItemDto.SatuanPack = ((ItemDTO) param).SatuanPack;
            frmAdd = new Add();
            frmAdd.Show();
        }


        private void SearchSubGroup(Object param)
        {
            mode = Mode.Search;
            ItemDto = new ItemDTO();
            frmSearch = new Search();
            frmSearch.Show();
        }


        private void SearchResult(Object param)
        {
             criteria = new Dictionary<string, object>();

            foreach (PropertyInfo prop in ItemDto.GetType().GetProperties())
            {
                if (prop.PropertyType == typeof (Decimal))
                {
                    if ((Decimal) prop.GetValue(ItemDto, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int32))
                {
                    if ((Int32) prop.GetValue(ItemDto, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Int64))
                {
                    if ((Int64) prop.GetValue(ItemDto, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (Double))
                {
                    if ((Double) prop.GetValue(ItemDto, null) == 0) continue;
                }
                if (prop.PropertyType == typeof (String))
                {
                    if (String.IsNullOrEmpty((String) prop.GetValue(ItemDto, null))) continue;
                }
                if (prop.PropertyType == typeof (DateTime))
                {
                    if (prop.GetValue(ItemDto, null).ToString().Contains("0001")) continue;
                }
                if (prop.GetValue(ItemDto, null) == null) continue;
                if (prop.PropertyType.Name == "No") continue;

                if (prop.PropertyType.Name.ToLower().Contains("dto"))
                {
                    foreach (PropertyInfo propertyInfo in prop.GetValue(ItemDto, null).GetType().GetProperties()
                        )
                    {
                        if (propertyInfo.Name.ToLower().Contains("id") || propertyInfo.Name.ToLower().Contains("kode") ||
                            propertyInfo.Name.ToLower().Contains("serial") ||
                            propertyInfo.Name.ToLower().Contains("code"))
                        {
                            criteria.Add(prop.Name, propertyInfo.GetValue(prop.GetValue(ItemDto, null), null));
                            break;
                        }
                    }
                }
                else
                {
                    criteria.Add(prop.Name, prop.GetValue(ItemDto, null));
                }
            }

            expression = string.Empty;
            if (frmSearch.rblOr.IsChecked ?? false) expression = "OR";
            else expression = "AND";
            ItemSearch(criteria, expression,1);
        }

        private void ItemSearch(Dictionary<String, Object> criteria, string expression, int page)
        {
            frmSearch.DialogResult = true;
            IsBusy = true;
            Complete(this);
            client.GetListByCriteriaCompleted += client_GetListByCriteriaCompleted;
            client.GetListByCriteriaAsync(criteria, expression, page,criteria);
        }

        private void client_GetListByCriteriaCompleted(object sender, GetListByCriteriaCompletedEventArgs e)
        {
            client.GetListByCriteriaCompleted -= client_GetListByCriteriaCompleted;
            Items = new PagedCollectionView(e.Result);
            if (RecordCount != e.recordCount)
            {
                RecordCount = e.recordCount;
                CreatePageNumber();
            }
            IsBusy = false;
            criteria = (Dictionary<String,Object>)e.UserState;
        }

        private void GetGroupList()
        {
            SubGroupClient.GetAllSubGroupCompleted += new EventHandler<GetAllSubGroupCompletedEventArgs>(SubGroupClient_GetAllSubGroupCompleted);
            SubGroupClient.GetAllSubGroupAsync();
        }

        void SubGroupClient_GetAllSubGroupCompleted(object sender, GetAllSubGroupCompletedEventArgs e)
        {
            SubGroupClient.GetAllSubGroupCompleted -= new EventHandler<GetAllSubGroupCompletedEventArgs>(SubGroupClient_GetAllSubGroupCompleted);
            SubGroups = new ObservableCollection<SubGroupDTO>((from g in e.Result
                                                               select
                                                                   new SubGroupDTO
                                                                   {
                                                                       Description = g.Description,
                                                                       SubGroupID = g.SubGroupID,
                                                                       SubGroupName = g.SubGroupName
                                                                   }));
            if (mode == Mode.Edit)
            {
                if (ItemDto.SubGroup == null) return;
                ItemDto.SubGroup = SubGroups.FirstOrDefault(x => x.SubGroupID == ItemDto.SubGroup.SubGroupID);
            }
        }

        private void GroupClient_GetListCompleted(object sender, SubGroupServices.GetListCompletedEventArgs e)
        {
            
        }

        private void CreatePageNumber()
        {
            Pages = new ObservableCollection<int>();
            for (int i = 0; i < RecordCount; i++)
            {
                Pages.Add(i);
            }
            PageSources = new PagedCollectionView(Pages);
        }


        private void PageIndexChanged(Object pageIndex)
        {
            //Jika Pertama kali jangan di Getlagi
            ItemDto = null;
            if (Items != null && CurrentPage != (int) pageIndex)
            {
                CurrentPage = (int) pageIndex;
                if (mode == Mode.Search)
                    ItemSearch(criteria, expression, (int)pageIndex + 1);
                else if (String.IsNullOrEmpty(PropertySort))
                    GetList((int) pageIndex + 1, null);
                else GetList((int) pageIndex + 1, PropertySort);
            }
        }


        public bool CanPageIndexChanged(Object param)
        {
            return true;
        }


        public bool CanSave(Object param)
        {
            return true;
        }


        public bool CanNew(Object param)
        {
            return true;
        }

        public bool CanEdit(Object param)
        {
            return true;
        }


        public bool CanUnload(Object param)
        {
            return true;
        }


        public bool CanSearch(Object param)
        {
            return true;
        }

        public bool CanSearchResult(Object param)
        {
            return true;
        }


        public void Release(Object param)
        {
            param = null;
            ItemDto = null;
            OrderType = null;
            PropertySort = null;
            mode = Mode.Idle;
        }


        public void Refresh()
        {
            if (Items == null)
                GetList(1, null);
            else
                Complete(this);
        }


        private void GetSatuanList()
        {
            SatuanClient.GetAllSatuanCompleted += SatuanPackClient_GetAllSatuanPackCompleted;
            SatuanClient.GetAllSatuanAsync();
        }

        private void SatuanPackClient_GetAllSatuanPackCompleted(object sender, GetAllSatuanCompletedEventArgs e)
        {
            SatuanClient.GetAllSatuanCompleted -= SatuanPackClient_GetAllSatuanPackCompleted;
            Satuans = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.Satuan == null || ItemDto.SatuanPack == null) return;
                ItemDto.Satuan =
                    Satuans.FirstOrDefault(s => s.KodeSatuan == ItemDto.Satuan.KodeSatuan);
                ItemDto.SatuanPack =
                 Satuans.FirstOrDefault(s => s.KodeSatuan == ItemDto.SatuanPack.KodeSatuan);
            }
        }


        private void GetCOAInventory()
        {
            CoaClient.GetCoaInventoryCompleted += CoaClient_GetCoaInventoryCompleted;
            CoaClient.GetCoaInventoryAsync();
        }

        void CoaClient_GetCoaInventoryCompleted(object sender, GetCoaInventoryCompletedEventArgs e)
        {
            CoaClient.GetCoaInventoryCompleted -= CoaClient_GetCoaInventoryCompleted;
            CoasInventory = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.CoaInventory != null)
                    ItemDto.CoaInventory = CoasInventory.FirstOrDefault(x => x.AccountNumber == ItemDto.CoaInventory.AccountNumber);
            }
        }

        private void GetCOAHpp()
        {
            CoaClient.GetCoaHppCompleted += CoaClient_GetCoaHppCompleted;
            CoaClient.GetCoaHppAsync();
        }

        private void CoaClient_GetCoaHppCompleted(object sender, GetCoaHppCompletedEventArgs e)
        {
            CoaClient.GetCoaHppCompleted -= CoaClient_GetCoaHppCompleted;
            CoasHpp = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.CoaHpp != null)
                    ItemDto.CoaHpp = CoasHpp.FirstOrDefault(x => x.AccountNumber == ItemDto.CoaHpp.AccountNumber);
            }
        }

        private void GetCOASales()
        {
            CoaClient.GetCoaSalesCompleted +=CoaClient_GetCoaSalesCompleted;
            CoaClient.GetCoaSalesAsync();
        }

        private void CoaClient_GetCoaSalesCompleted(object sender, GetCoaSalesCompletedEventArgs e)
        {
            CoaClient.GetCoaSalesCompleted += CoaClient_GetCoaSalesCompleted;
            CoasSales = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.CoaSales != null)
                    ItemDto.CoaSales = CoasSales.FirstOrDefault(x => x.AccountNumber == ItemDto.CoaSales.AccountNumber);
            }
        }

        private void GetCOASalesReturn()
        {
            CoaClient.GetCoaSalesReturnCompleted += CoaClient_GetCoaSalesReturnCompleted;
            CoaClient.GetCoaSalesReturnAsync();
        }

        private void CoaClient_GetCoaSalesReturnCompleted(object sender, GetCoaSalesReturnCompletedEventArgs e)
        {
            CoaClient.GetCoaSalesReturnCompleted -= CoaClient_GetCoaSalesReturnCompleted;
            CoasSalesReturn = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.CoaSalesReturn != null)
                    ItemDto.CoaSalesReturn = CoasSalesReturn.FirstOrDefault(x => x.AccountNumber == ItemDto.CoaSalesReturn.AccountNumber);
            }
        }

        private void GetCOAExpense()
        {
            CoaClient.GetCoaExpenseCompleted +=CoaClient_GetCoaExpenseCompleted;
            CoaClient.GetCoaExpenseAsync();
        }

        private void CoaClient_GetCoaExpenseCompleted(object sender, GetCoaExpenseCompletedEventArgs e)
        {
            CoaClient.GetCoaExpenseCompleted -= CoaClient_GetCoaExpenseCompleted;
            CoasExpense = e.Result;
            if (mode == Mode.Edit)
            {
                if (ItemDto.CoaExpense != null)
                    ItemDto.CoaExpense = CoasExpense.FirstOrDefault(x => x.AccountNumber == ItemDto.CoaExpense.AccountNumber);
            }
        }

        
        public void SendEmail(Object param)
        {
            ChooseDestination chooseDestination = new ChooseDestination();
            chooseDestination.Show();
            EventAggregator.RegisterMessage("SendDestination", (x) =>
                                                                   {
                                                                       IsBusy = true;
                                                                       client.SendEmailCompleted += client_SendEmailCompleted;
                                                                       client.SendEmailAsync(param as ItemDTO,(x as WarehouseDTO).EmailFolder);
                                                                   });
           
            
            
        }

        private void client_SendEmailCompleted(object sender, ItemServices.SendEmailCompletedEventArgs e)
        {
            IsBusy = false;
            client.SendEmailCompleted -= client_SendEmailCompleted;
            if (e.Result) MessageBox.Show("Pengiriman Selesai");
        }
    }

    public class ItemWrapViewModel : ViewModelBase
    {
        private readonly ItemServicesClient client;

        public ItemWrapViewModel()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                EditCommand = new DelegateCommand(Edit, CanEditCommand);
                DeleteCommand = new DelegateCommand(Delete, CanDeleteCommand);
                client = new ItemServicesClient();
            }
        }

        public ItemDTO ItemDto { get; set; }
        public ICommand EditCommand { get; set; }
        public ICommand DeleteCommand { get; set; }


        public bool CanEditCommand(Object param)
        {
            return true;
        }

        public bool CanDeleteCommand(Object param)
        {
            return true;
        }


        public void Edit(Object param)
        {
            ItemViewModel.EditSubGroup(param);
        }

        public void Delete(Object param)
        {
            DeleteConfirmation deleteConfirmation = new DeleteConfirmation();
            deleteConfirmation.Show();
            EventAggregator.RegisterMessage("ApprovalSucceeded",(x)=>
                                                                    {
                                                                        deleteConfirmation.Close();
                                                                        client.DeleteCompleted += client_DeleteCompleted;
                                                                        client.DeleteAsync((ItemDTO)param);                                                         
                                                                    });
           
        }

        private void client_DeleteCompleted(object sender, DeleteCompletedEventArgs e)
        {
            client.DeleteCompleted -= client_DeleteCompleted;
            if (e.Result) MessageBox.Show("Delete Success!");
            else
                MessageBox.Show(e.err);
            ItemViewModel.mode = Mode.Idle;
            var VM = new ItemViewModel();
        }
    }


    public class SubGroupConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null)
            {
                return ((dynamic) value).SubGroupName;
            }
            else
            {
                return string.Empty;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}